package com.learn.boot.datasource.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.druid.stat.DruidDataSourceStatManager;
import com.learn.boot.datasource.domain.DataSourceProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Map;
import java.util.Set;


/**
 * 实现动态数据源，根据AbstractRoutingDataSource路由到不同数据源中
 *
 * @author: MI
 * @email: 448341911@qq.com
 * @createTime: 2023/12/16 12:29
 * @updateUser: cong zhi
 * @updateTime: 2023/12/16 12:29
 * @updateRemark: 修改内容
 * @version: v1.0
 */
@Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {

    private boolean debug = true;



    private volatile  Map<Object, Object> targetDataSources;

    public DynamicRoutingDataSource(DataSource defaultDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultDataSource);
        super.setTargetDataSources(targetDataSources);
        this.targetDataSources = targetDataSources;
    }

    @Override
    public void setTargetDataSources(Map<Object, Object> param) {
        super.setTargetDataSources(param);
        this.targetDataSources = param;
    }
    /**
     * 创建数据源
     * @param dataSourceProperties
     */
    public void createDataSource(DataSourceProperties dataSource) {
        try {
            Class.forName(dataSource.getDriverClassName());
            Connection connection = DriverManager.getConnection(dataSource.getUrl(), dataSource.getUserName(), dataSource.getPassWord());
            if(connection==null){
                log.error("数据源配置有错误，DataSource：{}",dataSource);
            }else{
                connection.close();
            }

            DruidDataSource druidDataSource = getDruidDataSource(dataSource);
            this.targetDataSources.put(dataSource.getDataSourceId(),druidDataSource);
            // 将map赋值给父类的TargetDataSources
            setTargetDataSources(this.targetDataSources);
            // 将TargetDataSources中的连接信息放入resolvedDataSources管理
            super.afterPropertiesSet();

        } catch (Exception e) {
            log.error("数据源创建失败",e);
        }
    }

    private static DruidDataSource getDruidDataSource(DataSourceProperties dataSource) throws SQLException {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setName(dataSource.getDataSourceId());
        druidDataSource.setDriverClassName(dataSource.getDriverClassName());
        druidDataSource.setUrl(dataSource.getUrl());
        druidDataSource.setUsername(dataSource.getUserName());
        druidDataSource.setPassword(dataSource.getPassWord());
        druidDataSource.setMaxActive(20);
        druidDataSource.setMinIdle(5);
        //获取连接最大等待时间，单位毫秒
        druidDataSource.setMaxWait(6000);
        String validationQuery = "select 1 from dual";
        //申请连接时执行validationQuery检测连接是否有效，防止取到的连接不可用
        druidDataSource.setTestOnBorrow(true);
        druidDataSource.setValidationQuery(validationQuery);
        druidDataSource.init();
        return druidDataSource;
    }

    /**
     * 存储我们注册的数据源
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {

        String datasourceId = DataSourceContextHolder.getDataSource();
        if(!StringUtils.isEmpty(datasourceId)){
            Map<Object, Object> map = this.targetDataSources;
            if(map.containsKey(datasourceId)){
                log.info("当前数据源是：{}",datasourceId);
            }else{
                log.info("不存在数据源：{}",datasourceId);
                return null;
            }
        }else{
            log.info("当前是默认数据源");
        }
        return datasourceId;
    }

    /**
     * 校验数据源是否存在
     *
     * @param key 数据源保存的key
     * @return 返回结果，true：存在，false：不存在
     */
    public void checkCreateDataSource(DataSourceProperties dataSource){
        String datasourceId = dataSource.getDataSourceId();
        Map<Object, Object> map = this.targetDataSources;
        if(map.containsKey(datasourceId)){
            //这里检查一下之前创建的数据源，现在是否连接正常
            DruidDataSource druidDataSource = (DruidDataSource) map.get(datasourceId);
            boolean flag = true;
            DruidPooledConnection connection = null;
            try {
                connection = druidDataSource.getConnection();
            } catch (SQLException throwables) {
                //抛异常了说明连接失效吗，则删除现有连接
                log.error(throwables.getMessage());
                flag = false;
                delDataSources(datasourceId);
                //
            }finally {
                //如果连接正常记得关闭
                if(null != connection){
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        log.error(e.getMessage());
                    }
                }
            }
            if(!flag){
                createDataSource(dataSource);
            }
        }else {
            createDataSource(dataSource);
        }
    }

    /**
     * 删除数据源
     * @param datasourceId
     */
    private void delDataSources(String datasourceId) {
        Map<Object, Object> map = this.targetDataSources;
        Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances();
        for (DruidDataSource dataSource : druidDataSourceInstances) {
            if (datasourceId.equals(dataSource.getName())) {
                map.remove(datasourceId);
                //从实例中移除当前dataSource
                DruidDataSourceStatManager.removeDataSource(dataSource);
                // 将map赋值给父类的TargetDataSources
                setTargetDataSources(map);
                // 将TargetDataSources中的连接信息放入resolvedDataSources管理
                super.afterPropertiesSet();
            }
        }
    }


}
